Skip to content

docs(driver-sql): the lookup arm no longer claims a platform id is 26 characters - #16116

Merged
zhuangjianguo merged 1 commit into
mainfrom
claude/issue-15522-platform-id-length-prose-vs-constant
Sep 6, 2026
Merged

docs(driver-sql): the lookup arm no longer claims a platform id is 26 characters#16116
zhuangjianguo merged 1 commit into
mainfrom
claude/issue-15522-platform-id-length-prose-vs-constant

Conversation

@zhuangjianguo

Copy link
Copy Markdown
Collaborator

Fixes #15522

Deliverable 1 first — the reading, before either number moved

The card and the claim both forbade touching either number until the id's provenance was established, and offered two readings. Measured on origin/main 64011dd3f: neither holds, and the third answer is what shipped.

probe result control
git grep -rni ulid repo-wide, lockfile excluded 0 nanoid on the same instrument → 50 (fires)
git log -p --follow over sql-driver.ts, all const DEFAULT_ID_LENGTH lines exactly one + line (= 16), no - line ever
DEFAULT_ID_LENGTH across every driver driver-sql 16 · driver-mongodb 16 · driver-turso 16 driver-memory mints name-timestamp-counter — a different shape entirely
nanoid( in sql-driver.ts exactly 3, all in the else if (id === undefined) fallback branch re-derived, complete not sampled
id-minting above the driver none — engine.ts hands the row to driver.create unaltered; its only generator is generateEventUuid for DataEvent.id

And the firing empirical control — the real SqlDriver driven against SQLite, one write supplying an id and one not:

PROBE-CREATE [{"name":"a","id":"CALLER_SUPPLIED_ID","len":18},
              {"name":"b","id":"vst5t2rcKZb8TGDl","len":16},
              {"name":"c","id":"ALIAS_SUPPLIED_ID","len":17}]
PROBE-BULK   [{"name":"u","id":"-hyYncA6knoVTp8J","len":16},
              {"name":"x","id":"7vnoM1WTP6VtCuuz","len":16},
              {"name":"y","id":"yN6YwQhse7V9MDek","len":16},
              {"name":"z","id":"SUPPLIED_B","len":10}]
  • Reading 1 is false. Nothing mints a 26-character ULID above the driver; no ULID exists anywhere in this repo.
  • Reading 2 is false. The id shape never moved — DEFAULT_ID_LENGTH has been 16 for the whole life of the file, and the sentence was written 2026-08-24 (c49afd088), after the constant was already 16. Neither site is residue.
  • What actually held: the number was wrong when written, and at the real numbers the worked example did not even hold — a 16-character id fits in varchar(20), so the ERROR 1406 Data too long the comment promised would not have fired.

The STOP CONDITION is not reached. The fix touches prose only; DEFAULT_ID_LENGTH stays 16 and all three mint sites are untouched. No data-shape change, no manual floor.

The argument is kept, and stated in the stronger form the measurement licenses

The sentence exists to argue that maxLength must not bind a reference column. That argument never depended on 26 — and it is stronger without it: an id's width is not a fixed number at all. The driver mints 16 when the caller supplies none, and stores a supplied id verbatim at whatever width the caller chose, so no maxLength can be known to fit one.

Scope, and the one bounded in-place fix

  • packages/drivers/driver-sql/src/sql-driver.ts — the card's site, in the case 'lookup': case 'user': arm.
  • packages/drivers/driver-sql/src/sql-driver-string-maxlength-varchar.test.tsthe bounded in-place fix, named here with its evidence. The same sentence, same package, same gate family, same defect class; it is a comment, not an asserted value (the assertion is expect(shapes.a_lookup).toBe('varchar(255)') and is untouched). Leaving it would have shipped a driver whose own pin test's comment contradicted it.
  • Boundary scan (git grep "platform id is 26 characters", repo-wide): after this PR the phrase survives at four packages/cli source sites and two CHANGELOG entries. The CLI four are a different package and a different verification surface, so they are ⛔ filed as [finding] four packages/cli sites cite driver-sql's lookup arm for "a platform id is 26 characters" — the platform mints 16, and stores a supplied id at any width #16114 rather than fixed here; the CHANGELOGs are historical records and are ⛔ not editable.

⭐ Those four each cite this driver arm by name as their authority. That is exactly the harm the card was filed on — "a citation waiting to be relied on again" — already realized, in a second package, four times over. The corrected comment now points at #16114 so the chain is traceable.

The card's own measurement, corrected

The card, triage and the claim all recorded two prose sites saying 26. Only one is about ids. The other, sql-driver.ts * that exactly 26 characters fold, without knowing the server's locale., is about the 26 letters of the ASCII alphabet in the LIKE case-folding map (ASCII_UPPER_LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') — a coincidental hit from a bare grep "26 characters", carried forward by three seats. ⛔ It is deliberately untouched.

Clause ② — no, measured on both limbs

  • Limb 1 (prose): no. The diff is 37 changed lines, 0 of them non-comment — mechanically checked, every added and removed line matches ^[+-]\s*//. Zero executable tokens.
  • Limb 2 (would the fix change what the driver mints): does not arise — measured false above. DEFAULT_ID_LENGTH and all three nanoid(DEFAULT_ID_LENGTH) sites are byte-untouched.
  • Published-surface ablation, with both legs proven: mutate (swap both files back to 64011dd3f) → mutation confirmed on disk by anchored counts (#15522 1→0, claim phrase 0→1) and blob hash ce45e8de != HEAD blob 4f3fcd6e → rebuild → restore → git diff HEAD empty and blob 4f3fcd6e == HEAD blob → rebuild. files[] publishes dist; both declaration files dist/index.d.ts and dist/index.d.mts are byte-identical across the ablation (28f610ed), with the head rebuild reproducing the same hash as the control. The only published bytes that move are the sourcesContent blobs inside dist/index.js.map / index.mjs.map — a verbatim copy of the source comment, not a surface.

⇒ Comment-only, publishes no API ⇒ skip-changeset, applied additively and read back.

Verification — all at d337f421d

  • pnpm --filter '@objectstack/driver-sql^...' build — VERDICT command-exit 0
  • tsc --noEmit (driver-sql) — exit 0, and --listFiles confirms both edited files are in the program (1 hit each), so this is a measurement about them and not a vacuous pass
  • vitest run src/sql-driver-string-maxlength-varchar.test.ts src/sql-driver-11567-lookup-no-foreign-key.test.ts11 passed, 2 skipped (the skips are the live MySQL/Postgres cells, no live server here)
  • Gates, exit codes captured before any pipe, all 0: check:nul-bytes · check-comment-mask-adoption (+ self-test) · check-comment-mask-corpus · check-keyed-text-bounds (+ self-test) · check:driver-conformance · check:tenant-chokepoint · check:test-source-alias · check:cross-package-test-inputs · check:doc-authoring · check:published-files · check:dts-closure · check:objectql-double-limit · check:where-matcher · check:single-claim-paths · check-closing-keyword-parity · check-empty-changeset · check-changeset-no-major · check-changeset-fixed · check-adr-0087-registration
  • check-partof-closing-keyword.mjs first returned NOT WIRED (no PR_BODY/PR_NUMBER) — a prerequisite failure and ⛔ not a verdict, so it is not reported as one. Re-run with PR_BODY set to this exact body: exit 0, ✓ check:partof-closing-keyword: this PR carries no Part-of/closing-keyword contradiction.
  • Declared narrowing: the derived family is 40 matched families / 122 runnable rows. The set above is the subset this comment-only diff can implicate plus the mandatory ones; the farm is CI's, which runs it exactly once regardless. Family re-derived after the final commit with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack — provenance line confirms objectstack-ai/objectstack at d337f421d, change set 2 paths vs merge base 64011dd3f.

Generated by Claude Code

… characters

`createColumn`'s `case 'lookup': case 'user':` arm argued that `maxLength`
must not bind a reference column, and backed it with a worked example: a
26-character ULID refused by `varchar(20)` as `ERROR 1406 Data too long`.
That number is not this platform's, and at the real one the example did not
hold — 16 characters fit in `varchar(20)`.

Measured, not inferred:

  - `DEFAULT_ID_LENGTH` is 16, and `git log -p --follow` over the whole life
    of the file yields exactly one `+const DEFAULT_ID_LENGTH` line and no `-`
    line: it has never been anything else. The id shape never moved, so
    neither site was residue.
  - No ULID is minted anywhere in the repo. `git grep -rni ulid` excluding
    the lockfile returns 0, with `nanoid` as the firing control (50).
  - Driving the real `SqlDriver` against SQLite: a write supplying no id gets
    a 16-character nanoid; a write supplying one has it stored verbatim at
    whatever width the caller chose (10-, 17- and 18-character ids all landed
    unaltered). Nothing on this path bounds an id's width at all.

The argument the sentence supports is unchanged and is now stated in the
stronger form the measurement licenses: an id's width is not a fixed number,
so no `maxLength` can be known to fit one. Nothing about what the driver
mints changes; the diff is comments only.

The sibling comment in `sql-driver-string-maxlength-varchar.test.ts` carried
the same number and moves with it. Four `packages/cli` sites cite this arm by
name for it and are filed as #16114 rather than fixed here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ARYe3yQTQCUFm5qPYNgKaJ
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 6, 2026
@github-actions github-actions Bot added the size/s label Sep 6, 2026
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to listnot a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

What this run could not see
  • the SDK route bridge reached 61 of 219 client-bound route-ledger rows — the other 158 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 158: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 10 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json a4816a79d0396d0fd10696cdf95d66e55aef92d3packageMentionDocs.

Which tree this was computed on

This run read content/docs from 8b4325de538b4cecbf5f3847d4aacb8f27ad01f1 — the merge of head d337f421d68c485050ea56bb4b2b28d2c26d705d into base a4816a79d0396d0fd10696cdf95d66e55aef92d3, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 8b4325de538b4cecbf5f3847d4aacb8f27ad01f1 && git checkout 8b4325de538b4cecbf5f3847d4aacb8f27ad01f1
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin a4816a79d0396d0fd10696cdf95d66e55aef92d3 d337f421d68c485050ea56bb4b2b28d2c26d705d && git checkout -B drift-repro a4816a79d0396d0fd10696cdf95d66e55aef92d3 && git merge --no-ff d337f421d68c485050ea56bb4b2b28d2c26d705d

node scripts/docs-audit/affected-docs.mjs --json a4816a79d0396d0fd10696cdf95d66e55aef92d3

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@github-actions github-actions Bot added the tests label Sep 6, 2026
@zhuangjianguo
zhuangjianguo marked this pull request as ready for review September 6, 2026 03:01
@zhuangjianguo
zhuangjianguo added this pull request to the merge queue Sep 6, 2026
Merged via the queue into main with commit 658262e Sep 6, 2026
39 checks passed
@zhuangjianguo
zhuangjianguo deleted the claude/issue-15522-platform-id-length-prose-vs-constant branch September 6, 2026 03:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

2 participants